#ifndef __WIZ_BNF_OBJECT_WITH_ID_HPP__SHANHAOBO_19800429__
#define __WIZ_BNF_OBJECT_WITH_ID_HPP__SHANHAOBO_19800429__

#include "../../Core/Container/WizDataTypeArray.hpp"
#include "../../DataType/SmartPtr/SharedPtr/WizDataTypeSharedPtr.hpp"

#include "../../System/WizLock.hpp"

namespace Wiz
{
    namespace BNF
    {
        namespace ObjectWithID
        {
            namespace Supply
            {
                template <typename IdT = ::Wiz::Size::Type>
                struct Type
                {
                    typedef IdT                             tObjectID;
                    typedef ::Wiz::Array::Type<tObjectID>   tObjectIDArray;

                    Type() : m_MaxID(tObjectID())
                    {}

                    ::Wiz::Lock::Type   m_Lock;

                    tObjectID           m_MaxID;
                    tObjectIDArray      m_FreeIDS;

                    tObjectID           Acquire()
                    {
                        ::Wiz::ScopedLock::Type LLock(m_Lock);

                        if (m_FreeIDS.Size())
                        {
                            tObjectID ID = *m_FreeIDS.RBegin();
                            m_FreeIDS.PopBack();
                            return ID;
                        }
                        else
                        {
                            if (m_FreeIDS.Capacity() <= m_MaxID)
                            {
                                m_FreeIDS.Reserve(m_MaxID * 3 / 2 + 1);
                            }
                            return ++m_MaxID;
                        }
                    }
                    ::Wiz::Void::Type   Release(tObjectID ID)
                    {
                        ::Wiz::ScopedLock::Type LLock(m_Lock);

                        if (m_MaxID == ID)
                        {
                            m_MaxID--;
                        }
                        else
                        {
                            m_FreeIDS.PushBack(ID);
                        }
                    }
                };
            } /// end of namespace Supply

            namespace Base
            {
                template <typename TagT, typename IdT = ::Wiz::Size::Type>
                struct Type
                {
                    typedef TagT            tTag;
                    typedef IdT             tObjectID;
                    typedef Type<TagT, IdT> tThis;

                protected:
                    tObjectID           Acquire()
                    {
                        {
                            ::Wiz::ScopedLock::Type LLock(LockInstance());

                            static ::Wiz::SharedPtr::Type<::Wiz::BNF::ObjectWithID::Supply::Type<IdT>>
                                StaticSupply;

                            if (StaticSupply.NotValid())
                            {
                                StaticSupply.Reset(new ::Wiz::BNF::ObjectWithID::Supply::Type<IdT>());
                            }
                            m_IDSupply = StaticSupply;
                        }

                        return m_IDSupply->Acquire();
                    }
                    ::Wiz::Void::Type   Release(tObjectID ID)
                    {
                        m_IDSupply->Release(ID);
                    }
                    tThis& operator=(tThis const& Other)
                    {
                        m_IDSupply = Other.m_IDSupply;
                        return *this;
                    }
                private:
                    static ::Wiz::Lock::Type &LockInstance()
                    {
                        static ::Wiz::Lock::Type Lck;
                        return Lck;
                    }
                    ::Wiz::SharedPtr::Type<::Wiz::BNF::ObjectWithID::Supply::Type<IdT>> m_IDSupply;
                };
            } /// end of namespace Base

            template<class TagT, typename IdT = ::Wiz::Size::Type>
            struct Type : public ::Wiz::BNF::ObjectWithID::Base::Type<TagT, IdT>
            {
                typedef Type<TagT, IdT>                                 tThis;
                typedef ::Wiz::BNF::ObjectWithID::Base::Type<TagT, IdT> tSuper;
                typedef IdT                                             tObjectID;

                Type() : m_ID(tSuper::Acquire())
                {}
                Type(tThis const& Other) : tSuper(Other), m_ID(Other.m_ID)
                {}
                tThis& operator=(tThis const& Other)
                {
                    tSuper::operator=(Other);
                    return *this;
                }
                ~Type()
                {
                    tSuper::Release(m_ID);
                }
                tObjectID GetObjectID() const
                {
                    return m_ID;
                }
            private:
                tObjectID const m_ID;
            };
        } /// end of namespace Object
    } /// end of namespace BNF
} /// end of namespace Wiz

#endif /*__WIZ_BNF_OBJECT_WITH_ID_HPP__SHANHAOBO_19800429__*/
